/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo All rights
 * reserved.
 */
package ac.jp.u_tokyo.SyncLib.dictionaries;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import ac.jp.u_tokyo.SyncLib.DynamicCombinatorBase;
import ac.jp.u_tokyo.SyncLib.Mod;
import ac.jp.u_tokyo.SyncLib.ModTypeUnsupportedException;
import ac.jp.u_tokyo.SyncLib.NullMod;
import ac.jp.u_tokyo.SyncLib.PrimMod;
import ac.jp.u_tokyo.SyncLib.Sync;
import ac.jp.u_tokyo.SyncLib.SyncFactory;
import ac.jp.u_tokyo.SyncLib.SynchronizationFailedException;
import ac.jp.u_tokyo.SyncLib.Value2Mod;
import ac.jp.u_tokyo.SyncLib.util.Helper;
import ac.jp.u_tokyo.SyncLib.util.Pair;
import ac.jp.u_tokyo.SyncLib.util.TwoIterable;

public abstract class DictMapCombinatorBase extends DynamicCombinatorBase
{

	protected int _nonDictCount;

	private int _dictCount;

	protected SyncFactory _innerSyncFactory;

	protected MatchedDict _matchedDict;

	protected static Object[] createInitialState(int dictCount, int nonDictCount)
	{
		Object[] newObjects = new Object[dictCount * 2 + nonDictCount];
		for (int i = 0; i < dictCount * 2; i++)
		{
			newObjects[i] = new HashMap();
		}
		return newObjects;
	}

	@Override
	public boolean isModConcerned(int index, Mod mod)
			throws ModTypeUnsupportedException
	{
		if (mod instanceof NullMod) return false;

		if (index < getDictCount())
		{
			if (false == mod instanceof DictMod)
				throw new ModTypeUnsupportedException();
			DictMod<Object, Object> dmod = (DictMod<Object, Object>) mod;
			for (Entry<Object, Mod<Object>> entry : dmod)
			{
				MatchedInfo matchedInfo = _matchedDict.getInfoByKey(index,
						entry.getKey());
				if (matchedInfo == null) return true; //new key
				if (matchedInfo.getSync().isModConcerned(index,
						entry.getValue())) return true;
			}
			return false;
		}
		else
		{
//			for (MatchedInfo info : _matchedDict.getAllMatchedInfo())
//			{
//				if (info.getSync().isModConcerned(
//						index - getDictCount() + getNonDictStartIndex(), mod))
					return true;
//			}
//			return false;
		}
	}

	protected int getDictCount()
	{
		return _dictCount;
	}

	protected static class MatchedInfo
	{
		Sync _sync;

		Object[] _keys;
		
		public MatchedInfo(Object[] keys, Sync sync)
		{
			super();
			_keys = keys;
			_sync = sync;
		}

		public Sync getSync()
		{
			return _sync;
		}

		public Object[] getKeys()
		{
			return _keys;
		}

		@Override
		public String toString()
		{
			return "{" + Helper.toString(_keys) + "}=" + _sync;
		}

	}

	class MatchedDict
	{

		private Map<Object, MatchedInfo>[] _addedMaps;

		private Set<Object>[] _removedSets;

		//
		//		int _dictCount;
		//
		public MatchedDict()
		{
			_addedMaps = new Map[getDictCount()];
			_removedSets = new Set[getDictCount()];
		}

		private Map<Object, MatchedInfo> getMatchedInfo(int i)
		{
			return (Map<Object, MatchedInfo>) getAttribute(getDictCount() + i);
		}

		private void modifyMatchedInfo(int i, Mod mod)
		{
			modifyAttribute(getDictCount() + i, mod);
		}

		public MatchedInfo getInfoByKey(int i, Object k)
		{
			MatchedInfo result;
			if (_addedMaps[i] != null
					&& (result = _addedMaps[i].get(k)) != null) return result;
			if (_removedSets[i] != null && _removedSets[i].contains(k))
				return null;
			return getMatchedInfo(i).get(k);
		}

		public void beforeSynchronization()
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				_addedMaps[i] = new HashMap<Object, MatchedInfo>();
				_removedSets[i] = new HashSet<Object>();
			}
		}

		public void syncSucceed()
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				DictModFactory<Object, MatchedInfo> mod = new DictModFactory<Object, MatchedInfo>();
				for (Entry<Object, MatchedInfo> entry : _addedMaps[i]
						.entrySet())
				{
					mod.addPut(entry.getKey(), new PrimMod<MatchedInfo>(entry
							.getValue()));
				}
				for (Object key : _removedSets[i])
				{
					mod.addRemove(key);
				}
				modifyMatchedInfo(i, mod.create());
			}
		}

		public void syncFailed()
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				_addedMaps[i] = null;
				_removedSets[i] = null;
			}
		}

//		public void addInfo(MatchedInfo m, boolean[] removed)
//		{
//			assert removed.length == getDictCount();
//			for (int i = 0; i < getDictCount(); i++)
//			{
//				if (removed[i]) continue;
//				_addedMaps[i].put(m.getKeys()[i], m);
//				_removedSets[i].remove(m.getKeys()[i]);
//			}
//		}
		
		public void addInfo(int index, MatchedInfo m)
		{
			_addedMaps[index].put(m.getKeys()[index], m);
			_removedSets[index].remove(m.getKeys()[index]);
		}


//		public void removeInfo(Object[] keys)
//		{
//			for (int i = 0; i < getDictCount(); i++)
//			{
//				_addedMaps[i].remove(keys[i]);
//				_removedSets[i].add(keys[i]);
//			}
//		}
		
		public void removeInfo(int index, Object key)
		{
			_addedMaps[index].remove(key);
			_removedSets[index].add(key);
		}


		public void removeAll()
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				_addedMaps[i].clear();
				_removedSets[i].addAll(getMatchedInfo(i).keySet());
			}
		}

		public Set<MatchedInfo> getAllMatchedInfo()
		{
			Set<MatchedInfo> result = new HashSet<MatchedInfo>();
			for (int i = 0; i < getDictCount(); i++) {
				
				for(MatchedInfo m : getMatchedInfo(i).values())
				{
					if (_removedSets[i] != null && _removedSets[i].contains(m.getKeys()[i])) continue;
					result.add(m);
				}
				if (_addedMaps[i] == null) continue;
				for(MatchedInfo m : _addedMaps[i].values())
				{
					if (_removedSets[i] != null && _removedSets[i].contains(m.getKeys()[i])) continue;
					result.add(m);
				}
			}
			
//			Set<MatchedInfo> removedSet = new HashSet<MatchedInfo>();
//			if (_removedSets[0] != null)
//			{
//				for (Object key : _removedSets[0])
//				{
//					removedSet.add(getMatchedInfo(0).get(key));
//				}
//			}
//			Set<MatchedInfo> result = new HashSet(getMatchedInfo(0).values());
//			if (_addedMaps[0] != null) result.addAll(_addedMaps[0].values());
//			result.removeAll(removedSet);
			return result;
		}
	}

	protected interface InfoProvider
	{
		Set<MatchedInfo> getInitialSyncsToInvoke()
				throws ModTypeUnsupportedException;

		Set<Object>[] getUnmatchedKeys();

		Map getDictValue(int i);

		Object getNonDictValue(int i);

		void initialize(Map<Object, Mod>[] dictmods, Mod[] nonDictMods);

		void applyResult(Mod[] result);
	}

	private abstract class InfoProviderBase implements InfoProvider
	{
		protected Map<Object, Mod>[] _dictmods;

		protected Mod[] _nonDictMods;

		public void initialize(Map<Object, Mod>[] dictmods, Mod[] nonDictMods)
		{
			_dictmods = dictmods;
			_nonDictMods = nonDictMods;
		}
	}

	protected class ResyncInfoProvider extends InfoProviderBase
	{

		Map[] dicts = new Map[getDictCount()];

		Object[] nonDictValues = new Object[_nonDictCount];

		public ResyncInfoProvider(Object[] values)
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				if (values[i] == null)
					dicts[i] = new HashMap();
				else
					dicts[i] = (Map) Helper.deepCopy(values[i]);
			}
			for (int i = 0; i < _nonDictCount; i++)
			{
				nonDictValues[i] = Helper.deepCopy(values[i + getDictCount()]);
			}
		}

		public void applyResult(Mod[] result)
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				modifyDictValue(i, Value2Mod.findMod(getDictValue(i), result[i]
						.apply(dicts[i])));
			}
			for (int i = 0; i < _nonDictCount; i++)
			{
				modifyNonDictValue(i, Value2Mod.findMod(
						DictMapCombinatorBase.this.getNonDictValue(i), result[i
								+ getDictCount()].apply(nonDictValues[i])));
			}
		}

		public void initialize(Map<Object, Mod>[] dictmods, Mod[] nonDictMods)
		{
			super.initialize(dictmods, nonDictMods);
			_matchedDict.removeAll();
		}

		public Map getDictValue(int i)
		{
			return dicts[i];
		}

		public Set<MatchedInfo> getInitialSyncsToInvoke()
		{
			return new HashSet<MatchedInfo>(0);
		}

		public Object getNonDictValue(int i)
		{
			return nonDictValues[i];
		}

		public Set<Object>[] getUnmatchedKeys()
		{
			Set<Object>[] result = new Set[getDictCount()];
			for (int i = 0; i < getDictCount(); i++)
			{
				result[i] = new HashSet<Object>();
				result[i].addAll(_dictmods[i].keySet());
				result[i].addAll(dicts[i].keySet());
			}
			return result;
		}
	}

	protected class SyncInfoProvider extends InfoProviderBase
	{

		public void applyResult(Mod[] result)
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				modifyDictValue(i, result[i]);
			}
			for (int i = 0; i < _nonDictCount; i++)
			{
				modifyNonDictValue(i, result[i + getDictCount()]);
			}
		}

		public Map getDictValue(int i)
		{
			return DictMapCombinatorBase.this.getDictValue(i);
		}

		public Set<MatchedInfo> getInitialSyncsToInvoke()
				throws ModTypeUnsupportedException
		{
			Set<MatchedInfo> result = getAffectedSyncFromDictMods(_dictmods);
			result.addAll(getAffectedSyncFromNonDictMods(_nonDictMods));
			return result;
		}

		public Object getNonDictValue(int i)
		{
			return DictMapCombinatorBase.this.getNonDictValue(i);
		}

		public Set<Object>[] getUnmatchedKeys()
		{
			Set<Object>[] result = new Set[getDictCount()];
			for (int i = 0; i < getDictCount(); i++)
			{
				result[i] = new HashSet<Object>();
				for (Object key : _dictmods[i].keySet())
				{
					if (_matchedDict.getInfoByKey(i, key) == null)
						result[i].add(key);
				}
			}
			return result;
		}

	}

	//	protected class ResynchronizationPerformer extends SynchronizationPerformer
	//	{
	//		ForMap[] dicts = new ForMap[getDictCount()];
	//	
	//		Object[] nonDictValues = new Object[_nonDictCount];
	//	
	//		public ResynchronizationPerformer(Object[] values, Mod[] modifications)
	//		{
	//			super(modifications);
	//			for (int i = 0; i < getDictCount(); i++)
	//			{
	//				if (values[i] == null)
	//					dicts[i] = new HashMap();
	//				else
	//					dicts[i] = (ForMap) Helper.deepCopy(values[i]);
	//			}
	//			for (int i = 0; i < _nonDictCount; i++)
	//			{
	//				nonDictValues[i] = Helper.deepCopy(values[i + getDictCount()]);
	//			}
	//		}
	//	
	//		@Override
	//		protected Set<MatchedInfo> getInitialSyncsToInvoke()
	//		{
	//			return new HashSet<MatchedInfo>(0);
	//		}
	//	
	//		@Override
	//		protected Set<Object>[] getUnmatchedKeys()
	//		{
	//			Set<Object>[] result = new Set[getDictCount()];
	//			for (int i = 0; i < getDictCount(); i++)
	//			{
	//				result[i] = new HashSet<Object>();
	//				result[i].addAll(dictmods[i].keySet());
	//				result[i].addAll(dicts[i].keySet());
	//			}
	//			return result;
	//		}
	//	
	//		@Override
	//		protected void doExtraInitialization()
	//		{
	//			_matchedDict.removeAll();
	//		}
	//	
	//		@Override
	//		protected void applyResult(Mod[] result)
	//		{
	//			for (int i = 0; i < getDictCount(); i++)
	//			{
	//				modifyDictValue(i, Value2Mod.findMod(getDictValue(i), result[i]
	//						.apply(dicts[i])));
	//			}
	//			for (int i = 0; i < _nonDictCount; i++)
	//			{
	//				modifyNonDictValue(i, Value2Mod.findMod(getNonDictValue(i),
	//						result[i + getDictCount()].apply(nonDictValues[i])));
	//			}
	//		}
	//	
	//		@Override
	//		protected ForMap internalGetDictValue(int i)
	//		{
	//			return dicts[i];
	//		}
	//	
	//		@Override
	//		protected Object internalGetNonDictValue(int i)
	//		{
	//			return nonDictValues[i];
	//		}
	//	
	//	}
	protected Mod[] doInvokeSync(Sync sync, Object[] keys, Mod[] mods)
			throws SynchronizationFailedException
	{
		return invokeSync(sync, mods);
	}

	protected Mod[] doInvokeResync(Sync newSync, Object[] selectedKeys,
			Mod[] mods, Object[] values) throws SynchronizationFailedException
	{
		return invokeResync(newSync, values, mods);
	}

	protected abstract class SynchronizationPerformer
	{
		protected Map<Object, Mod>[] dictmods;

		private Mod[] nonDictMods;

		private Set<MatchedInfo> syncsToInvoke;

		protected Set[] unmatchedKeys;

		protected InfoProvider _provider;

		public SynchronizationPerformer(Mod[] modifications,
				InfoProvider provider)
		{
			_provider = provider;
			_matchedDict.beforeSynchronization();
			dictmods = getDictModPart(modifications);
			nonDictMods = getNonDictModPart(modifications);

			_provider.initialize(dictmods, nonDictMods);
		}

		public Mod[] doSynchronization() throws SynchronizationFailedException
		{
			syncsToInvoke = _provider.getInitialSyncsToInvoke();
			assert syncsToInvoke != null;
			unmatchedKeys = _provider.getUnmatchedKeys();

			try
			{
				doOneTimeSynchronization();
			}
			catch (SynchronizationFailedException e)
			{
				_matchedDict.syncFailed();
				throw e;
			}
			_matchedDict.syncSucceed();
			Mod[] result = constructResult();
			_provider.applyResult(result);

			return result;

		}

		private Mod[] constructResult()
		{
			Mod[] result = new Mod[getDictCount() + _nonDictCount];
			for (int i = 0; i < getDictCount(); i++)
			{
				result[i] = new DictMod(dictmods[i]);
			}
			for (int i = 0; i < _nonDictCount; i++)
			{
				result[i + getDictCount()] = nonDictMods[i];
			}
			return result;
		}

		protected abstract void match() throws SynchronizationFailedException;

		private void doOneTimeSynchronization()
				throws SynchronizationFailedException
		{

			match();
			
			while (syncsToInvoke.size() > 0)
			{
				MatchedInfo m = syncsToInvoke.iterator().next();
//				System.out.println("**** Invoking" + Arrays.toString(m.getKeys()));
				Mod[] mods = prepareMods(m.getKeys());

				Mod[] result = doInvokeSync(m.getSync(), m.getKeys(), mods);

				fillSyncsToInvoke(mods, result);
				syncsToInvoke.remove(m);

				storeMods(m, result);
			}

		}

		protected void syncMatched(Object[] selectedKeys)
				throws SynchronizationFailedException,
				ModTypeUnsupportedException
		{
			Sync newSync = createSync();
			Mod[] mods = prepareMods(selectedKeys);
			Mod[] result = doInvokeResync(newSync, selectedKeys, mods,
					prepareValues(selectedKeys));
			createNewKeysIfNecessary(selectedKeys);
//			System.out.println("!!!!!Adding a new pair" + Arrays.toString(selectedKeys));
			storeMods(new MatchedInfo(selectedKeys, newSync), result);
			removeKeysFromUnmatched(selectedKeys);
			fillSyncsToInvoke(mods, result);
//			_matchedDict.addInfo(new MatchedInfo(selectedKeys, newSync), removed);
			putSyncIntoUse();
		}

		private void removeKeysFromUnmatched(Object[] keys)
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				unmatchedKeys[i].remove(keys[i]);
			}

		}

		protected abstract void createNewKeysIfNecessary(Object[] selectedKeys);

		protected Object[] prepareValues(Object[] selectedKeys)
		{
			Object[] result = new Object[getDictCount() + _nonDictCount];
			for (int i = 0; i < getDictCount(); i++)
			{
				if (selectedKeys[i] == null)
					result[i] = null;
				else
					result[i] = _provider.getDictValue(i).get(selectedKeys[i]);
			}
			for (int i = 0; i < _nonDictCount; i++)
			{
				result[i + getDictCount()] = _provider.getNonDictValue(i);
			}
			return result;
		}

		private Mod[] prepareMods(Object[] keys)
		{
			Mod[] mods = new Mod[getDictCount() + _nonDictCount];
			for (int i = 0; i < getDictCount(); i++)
			{
				if (keys[i] == null)
					mods[i] = NullMod.INSTANCE;
				else if ((mods[i] = dictmods[i].get(keys[i])) == null)
					mods[i] = NullMod.INSTANCE;
			}
			for (int i = 0; i < _nonDictCount; i++)
			{
				mods[i + getDictCount()] = nonDictMods[i];
			}
			return mods;
		}

		private void storeMods(MatchedInfo m, Mod[] result)
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				dictmods[i].put(m.getKeys()[i], result[i]);
//				if (PrimMod.NULL.equals(result[i])) {
//					_matchedDict.removeInfo(i, m.getKeys()[i]);
//				}
//				else if (false == result[i] instanceof NullMod) {
//					_matchedDict.addInfo(i, m);
//				}
				if (result[i].apply(_provider.getDictValue(i).get(m.getKeys()[i])) == null)
				{
					_matchedDict.removeInfo(i, m.getKeys()[i]);
				}
				else
				{
					_matchedDict.addInfo(i, m);
				}
			}
			for (int i = 0; i < _nonDictCount; i++)
			{
				nonDictMods[i] = result[i + getDictCount()];
			}
		}

		protected Pair<Integer, Object> getFirstUnmatched(Set[] unmatchedKeys)
		{
			for (int i = 0; i < getDictCount(); i++)
			{
				for (Object key : unmatchedKeys[i])
					return new Pair<Integer, Object>(i, key);
			}
			return null;
		}

		private boolean fillSyncsToInvoke(Mod[] mods, Mod[] result)
				throws ModTypeUnsupportedException
		{
			Mod[] difference = new Mod[_nonDictCount];
			boolean modified = false;
			for (int i = getDictCount(); i < getDictCount() + _nonDictCount; i++)
			{
				difference[i - getDictCount()] = result[i].subtract(mods[i]);
				if (false == difference[i - getDictCount()] instanceof NullMod)
				{
					modified = true;
				}
			}
			if (!modified) return false;
			syncsToInvoke.addAll(getAffectedSyncFromNonDictMods(difference));
			return true;
		}

		private Map<Object, Mod>[] getDictModPart(Mod[] modifications)
		{
			Map<Object, Mod>[] dictmods = new Map[getDictCount()];
			for (int i = 0; i < getDictCount(); i++)
			{
				dictmods[i] = new HashMap<Object, Mod>();
				for (Entry<Object, Mod<Object>> entry : DictMod
						.nullMod2NullDictMod((Mod<Map<Object, Object>>) modifications[i]))
				{
					dictmods[i].put(entry.getKey(), entry.getValue());
				}
			}
			return dictmods;
		}

		private Mod[] getNonDictModPart(Mod[] modifications)
		{
			Mod[] otherMods = new Mod[_nonDictCount];
			for (int i = 0; i < _nonDictCount; i++)
			{
				otherMods[i] = modifications[getDictCount() + i];
			}
			return otherMods;
		}

		//	/**
		//	 * 
		//	 * @param dictmods
		//	 * @param nonDictMods
		//	 * @param syncsToInvoke
		//	 * @param unmatchedKeys
		//	 * @return whether the synchronization need to be restarted or not
		//	 * @throws SynchronizationFailedException
		//	 */
		//	private boolean doMatchAndInvoke(ForMap<Object, Mod>[] dictmods,
		//			Mod[] nonDictMods, Set<MatchedInfo> syncsToInvoke,
		//			Set[] unmatchedKeys) throws SynchronizationFailedException
		//	{
		//		for (MatchedInfo m : syncsToInvoke)
		//		{
		//			Mod[] mods = prepareMods(m.getKeys(), dictmods, nonDictMods);
		//			
		//			Mod[] result = invokeSync(m.getSync(), mods);
		//			
		//			if (NonDictModsChanged(mods, result)) {
		//				return true;
		//			}
		//			
		//			storeMods(m, result, dictmods, nonDictMods);
		//		}
		//		
		//		Pair<Integer, Object> unmatched;
		//		while((unmatched = getFirstUnmatched(unmatchedKeys)) != null) {
		//			
		//		}
		//		
		//		return false;
		//	}
		//	
		//
		//	
		//	private void storeMods(MatchedInfo m, Mod[] result,
		//			ForMap<Object, Mod>[] dictmods, Mod[] nonDictMods)
		//	{
		//		for (int i = 0; i < getDictCount(); i++) {
		//			dictmods[i].put(m.getKeys()[i], result[i]);
		//		}
		//		for (int i = 0; i < _nonDictCount; i++) {
		//			nonDictMods[i] = result[i + getDictCount()];
		//		}
		//	}

		//	private Mod[] prepareMods(Object[] keys, ForMap<Object, Mod>[] dictmods,
		//			Mod[] nonDictMods)
		//	{
		//		Mod[] mods = new Mod[getDictCount() + _nonDictCount];
		//		for (int i = 0; i < getDictCount(); i++)
		//		{
		//			if ((mods[i] = dictmods[i].get(keys[i])) == null)
		//				mods[i] = NullMod.INSTANCE;
		//		}
		//		for (int i = 0; i < _nonDictCount; i++)
		//		{
		//			mods[i + getDictCount()] = nonDictMods[i];
		//		}
		//		return mods;
		//	}

	}

	protected Map getDictValue(int index)
	{
		return (Map) getAttribute(index);
	}

	protected void modifyDictValue(int index, Mod mod)
	{
		modifyAttribute(index, mod);
	}

	protected void modifyNonDictValue(int index, Mod mod)
	{
		modifyAttribute(index + getDictCount() * 2, mod);
	}

	protected Object getNonDictValue(int index)
	{
		return getAttribute(index + getDictCount() * 2);
	}

	private Sync _nextNewSync;

	public DictMapCombinatorBase(SyncFactory innerSync, int dictCount,
			int nonDictCount)
	{
		super(createInitialState(dictCount, nonDictCount));
		_innerSyncFactory = innerSync;
		_dictCount = dictCount;
		_nonDictCount = nonDictCount;
		_matchedDict = new MatchedDict();
		//		assert nonDictCount + dictCount == createSync().getParaCount();
	}

	protected Sync createSync()
	{
		if (_nextNewSync == null) _nextNewSync = _innerSyncFactory.create();
		return _nextNewSync;
	}

	protected void putSyncIntoUse()
	{
		_nextNewSync = null;
	}

	public int getParaCount()
	{
		return getDictCount() + _nonDictCount;
	}

	private Set<MatchedInfo> getAffectedSyncFromNonDictMods(Mod[] nonDictMods2)
			throws ModTypeUnsupportedException
	{
		Set<MatchedInfo> allInfo = _matchedDict.getAllMatchedInfo();
		Set<MatchedInfo> result = new HashSet<MatchedInfo>(allInfo.size());
		outter: for (MatchedInfo m : allInfo)
		{
			for (int i = 0; i < _nonDictCount; i++)
			{
				if (m.getSync().isModConcerned(i + getNonDictStartIndex(),
						nonDictMods2[i]))
				{
					result.add(m);
					continue outter;
				}
			}
		}
		return result;
	}

	protected int getNonDictStartIndex()
	{
		return getDictCount();
	}

	private Set<MatchedInfo> getAffectedSyncFromDictMods(
			Map<Object, Mod>[] dictmods) throws ModTypeUnsupportedException
	{
		Set<MatchedInfo> syncsToInvoke = new HashSet<MatchedInfo>();
		for (int i = 0; i < getDictCount(); i++)
		{
			for (Entry<Object, Mod> entry : dictmods[i].entrySet())
			{
				MatchedInfo infoByKey = _matchedDict.getInfoByKey(i, entry
						.getKey());
				if (infoByKey != null)
				{
					if (infoByKey.getSync().isModConcerned(i, entry.getValue()))
						syncsToInvoke.add(infoByKey);
				}
			}
		}
		return syncsToInvoke;
	}

}